package com.only.common.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author only
 * @date 2023/11/17
 * @description
 */
public class ListUtil {
    /**
     * 如果列表为 空列表，返回 None
     * 如果 list 的元素为空，返回 None
     * @param list
     * @return
     * @param <T>
     */
    public static <T> Optional<T> head(List<T> list) {
        if (CollectionUtils.isNotEmpty(list)) return Optional.ofNullable(list.get(0));
        return Optional.empty();
    }

    /**
     * 获取列表最后一个元素
     * 如果列表为空，返回 Optional.None
     * 如果列表的最后一个元元素为空，返回 Optional.None
     *
     * @param list
     * @return
     * @param <T>
     */
    public static <T> Optional<T> tail(List<T> list) {
        if (CollectionUtils.isEmpty(list)) return Optional.empty();

        return Optional.ofNullable(list.get(list.size() - 1));
    }

    /**
     * 过滤出有效的ID, 并且去重
     * @param list
     * @param mapper
     * @return
     * @param <T>
     */
    public static <T> List<String> filterValidId(List<T> list, Function<? super T, String> mapper) {
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }

        return list.stream().map(mapper).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
    }

    /**
     * 将符合其中一个 mapper 的数据进行返回
     * @param list
     * @param mappers
     * @return
     * @param <T>
     */
    @SafeVarargs
    public static <T> List<String> filterValidIdForFields(List<T> list, Function<? super T, String>... mappers) {
        List<String> result = new ArrayList<>();

        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }

        for (Function<? super T, String> mapper : mappers) {
            List<String> ret = list.stream().map(mapper).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
            result.addAll(ret);
        }

        return result.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 将 list 转为 Map， 如果有相同元素，取第一个
     * @param list
     * @param keyMapper
     * @return
     * @param <T>
     */
    public static <T> Map<String, T> toMap(List<T> list, Function<? super T, String> keyMapper) {
        BinaryOperator<T> miss = (t1, t2) -> t1;
        return list.stream().collect(Collectors.toMap(keyMapper, Function.identity(), miss));
    }

    public static <T> List<T> toList(Collection<T> list) {
        return new ArrayList<>(list);
    }

    /**
     * 过滤符合条件的元素
     * @param list
     * @param predicate
     * @return
     * @param <T>
     */
    public static <T> List<T> filter(List<T> list, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    public static <R, T> List<R> map(List<T> list, Function<? super T, R> mapper) {
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    public static <R, T> List<R> filterMap(List<T> list, Predicate<? super T> predicate, Function<? super T, R> mapper) {
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        return list.stream().filter(predicate).map(mapper).collect(Collectors.toList());
    }

    public static <T> List<T> flatten(List<List<T>> data) {
        if (CollectionUtils.isEmpty(data)) {
            return Lists.newArrayList();
        }

        return data.stream().flatMap(Collection::stream).collect(Collectors.toList());
    }

    public static <K, T> Map<K, List<T>> groupBy(List<T> list, Function<? super T, K> mapper) {
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }

        return list.stream().collect(Collectors.groupingBy(mapper));
    }

    public static <K, T, R> Map<K, List<R>> groupBy(List<T> list,
                                                    Function<? super T, K> keyMapper,
                                                    Function<? super T, R> valueMapper) {
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }

        Map<K, List<R>> ret = new HashMap<>();
        groupBy(list, keyMapper).forEach((k, v) ->  ret.put(k, map(v, valueMapper) ));
        return ret;
    }

    /**
     * 获取子队列
     * @param list
     * @param from 开始，包括
     * @param endIndex 结束，不包括
     */
    public static <T> List<T> subList(List<T> list, int from, int endIndex) {
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }

        if (from < 0) {
            from = 0;
        }

        if (endIndex < from) {
            endIndex = from;
        }

        if (endIndex > list.size()) {
            endIndex = list.size();
        }

        return list.subList(from, endIndex);
    }

    public static <T> Optional<T> findOne(List<T> list, Predicate<? super T> predicate) {
        return list.stream().filter(predicate).findFirst();
    }

    public static <T> boolean exist(List<T> list, Predicate<? super T> predicate) {
        return list.stream().anyMatch(predicate);
    }

    public static <T> void forEach(List<T> list, Consumer<? super T> action) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        list.forEach(action);
    }

    public static <T> long count(List<T> list, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list)) return 0L;

        return list.stream().filter(predicate).count();
    }

    public static <T> List<List<T>> slice(List<T> list, int stepFactor) {
        if (CollectionUtil.isEmpty(list)) {
            return Lists.newArrayList();
        }

        if (stepFactor >= list.size()) {
            return Collections.singletonList(list);
        }

        assert stepFactor >= 1;

        List<List<T>> ret = new ArrayList<>();
        int cursor = 0;
        while (cursor < list.size()) {
            int endCursor = cursor + stepFactor;
            List<T> stepRet = new ArrayList<>();
            for (; cursor < endCursor; cursor++) {
                if (cursor >= list.size()) break;
                stepRet.add(list.get(cursor));
            }

            if (!stepRet.isEmpty()) ret.add(stepRet);
        }

        return ret;
    }

    public static String listToString(List<String> list) {
        return ListAndStringConverter.listToString(list);
    }

    public static String listToString(List<String> list, String splitKey) {
        return ListAndStringConverter.listToString(list, splitKey);
    }
}
